
#include <vector>
#include <cassert>

#include <btBulletDynamicsCommon.h>

#include "triangulomalla.h"

namespace Fisica {

   TrianguloMalla::TrianguloMalla() : 
      triangulos(new btTriangleIndexVertexArray()),
      malla(0),
      huboCambio(false) {
   }

/*
 * "Posicion" es una posicion dentro del vector en la que contiene
 * la coordenada x del primer vertice.
 * En las siguientes dos posiciones, se deben encontrar las coordenadas y z
 * faltantes.
 *
 * Las siguientes coordenadas x y z del siguiente vertice comienzan en la
 * posicion "posicion"+"paso".
 *
 * Asi, el vertice i, se encuentra en la posicion "pos" + "paso" * i
 *
 * El proceso se repite hasta haber copiado "cantVertices" vertices
 * */
void TrianguloMalla::agregar(const std::vector<float> &vertices, unsigned posicion, 
      unsigned paso, unsigned cantVertices, Modo modo) {

   assert(paso >= 3);
   assert(cantVertices >= 3);
   assert(vertices.size() >= posicion + ((cantVertices-1) * paso) + 3);

   const int cantCoords = cantVertices * 3;
   const int cantTriangulos = cantVertices - 2;
   const int cantIndices = cantTriangulos * 3;

   coords.push_back(new std::vector<float>(cantCoords));
   indices.push_back(new std::vector<int>(cantIndices));

   float *scalar = &((*(coords.back()))[0]);
   int *index = &((*(indices.back()))[0]);

   for(int i = 0; i < cantCoords; i += 3, posicion += paso) {
      scalar[i    ] = vertices[posicion    ];
      scalar[i + 1] = vertices[posicion + 1];
      scalar[i + 2] = vertices[posicion + 2];
   }

   switch(modo) {
      case TriangleStrip:
         crearIndiceStrip(index, cantIndices, cantVertices);
         break;
      case TriangleFan:
         crearIndiceFan(index, cantIndices, cantVertices);
         break;
   }

   btIndexedMesh malla;

   malla.m_vertexType = PHY_FLOAT;

   malla.m_numTriangles = cantTriangulos;
   malla.m_triangleIndexBase = (const unsigned char*)index;
   malla.m_triangleIndexStride = 3 * sizeof(int);

   malla.m_numVertices = cantVertices;
   malla.m_vertexBase = (const unsigned char*)scalar;
   malla.m_vertexStride = 3 * sizeof(float);

   triangulos->addIndexedMesh(malla);

   huboCambio = true;
}

void TrianguloMalla::crearIndiceStrip(int *index, const int cantIndices, const int cantVertices) {
   for(int i = 0,j = 0; i < cantIndices; i += 3, ++j) {
      assert(0 <= j);
      assert(j+2 < cantVertices);

      index[i    ] = j    ;
      index[i + 1] = j + 1;
      index[i + 2] = j + 2;
   }
}

void TrianguloMalla::crearIndiceFan(int *index, const int cantIndices, const int cantVertices) {
   for(int i = 0,j = 0; i < cantIndices; i += 3, ++j) {
      assert(0 <= j);
      assert(j+2 < cantVertices);

      index[i    ] = 0    ;
      index[i + 1] = j + 1;
      index[i + 2] = j + 2;
   }
}

btCollisionShape& TrianguloMalla::makeForma() {
   assert(huboCambio or malla != 0);
   if(huboCambio) {
      delete malla;
      malla = new btBvhTriangleMeshShape(triangulos, true);
      huboCambio = false;
   }

   return *malla;
}

TrianguloMalla::~TrianguloMalla() {
   delete malla;
   delete triangulos;
   for(unsigned i = 0; i < coords.size(); ++i)
      delete coords[i];
   for(unsigned i = 0; i < indices.size(); ++i)
      delete indices[i];
}
}
